import datetime
from typing import Optional, Dict, Any

import bson
from pydantic import BaseModel as _BaseModel, Field
from bson import ObjectId


class PyObjectId(ObjectId):
    """自定义的objectid: 官方文档: https://docs.pydantic.dev/1.10/usage/types/#custom-data-types"""

    @classmethod
    def validate(cls, v):
        raise_error = False

        try:
            if isinstance(v, str):
                v = bson.ObjectId(v)

            if (
                    not isinstance(v, (bson.ObjectId, cls))
                    or not bson.ObjectId.is_valid(v)
            ):
                raise_error = True
        except bson.errors.InvalidId:
            raise_error = True

        if raise_error:
            raise ValueError("Invalid ObjectId")

        return v

    @classmethod
    def __get_validators__(cls):
        # one or more validators may be yielded which will be called in the
        # order to validate the input, each validator will receive as an input
        # the value returned from the previous validator
        yield cls.validate

    def __repr__(self):
        return str(self)


class DBModel(_BaseModel):
    create_time: datetime.datetime = Field(default_factory=datetime.datetime.now)
    delete_time: Optional[datetime.datetime] = None

    id: PyObjectId = Field(None, alias='_id')  # 可选的mongoid

    class Config:
        arbitrary_types_allowed = True

    def dict(self,*args, **kwargs) -> Dict[str, Any]:
        """mongodb, 如果没有设置_id, 让数据库自动插入"""
        res = super().dict(*args, **kwargs)
        if '_id' in res and res['_id'] is None:
            res.pop('_id')
        return res


class BaseModel(_BaseModel):

    class Config:
        arbitrary_types_allowed = True
        validate_assignment = True


if __name__ == '__main__':
    from typing import List

    class Permission(DBModel):
        download_folder: List[str]
        upload_folder: List[str]
        delete_folder: List[str]
        role_name: str

    # a = Permission(download_folder=['/'], upload_folder=['/'], delete_folder=['/'], role_name='admin', _id=ObjectId())
    a = Permission(download_folder=['/'], upload_folder=['/'], delete_folder=['/'], role_name='admin')
    print(a.id)
    print(a.dict(by_alias=True))
